import urllib
import pickle
from hash_table import ServerTable

import asyncore,socket

class cdb_net_client(asyncore.dispatcher):
	def __init__(self,addr,commands):
		self.commands = commands
		self.responses = []
		self.current_command = 0
		self.outbuffer = self.commands[self.current_command] + '\n'
		#print '!!!',self.outbuffer
		self.inbuffer = ''
		self.state = 1
		asyncore.dispatcher.__init__(self)
		
		self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
		self.connect(addr)

	def handle_connect(self):
		pass
	def handle_close(self):
		self.close()
	def handle_read(self):
		if self.state == 2:
			self.inbuffer += self.recv(1)
			if self.inbuffer.endswith('\n'):
				self.responses.append(self.inbuffer.strip())
				self.current_command +=1
				if self.current_command < len(self.commands):
					self.outbuffer = self.commands[self.current_command] +'\n'
					self.state = 1
				else:
					self.close()
	def writable(self):
		return (len(self.outbuffer)>0)
	def handle_write(self):
		if self.state == 1:
			#print '@@',self.outbuffer
			sent = self.send(self.outbuffer)
			self.outbuffer = self.outbuffer[sent:]
			if not self.writable():
				self.state = 2
	def run (self):
		asyncore.loop()




class cdb_client:
	def __init__(self,HashTable = ServerTable):
		self.servers = ServerTable()
	
	def add_server(self,addr):
		self.servers.add(addr)
	
	def encode(self,data):
		try:
			_data = data.__dict__
		except AttributeError:
			_data = data
		return urllib.quote(pickle.dumps(_data))
	
	def decode(self,s):
		return pickle.loads(urllib.unquote(s))
	
	def get(self,key):
		command = []
		command.append('GET '+ key )
		cdb_net = cdb_net_client(self.servers.get(key),command)
		cdb_net.run()
		
		if cdb_net.responses[0].startswith('NO'):
			return None
		return self.decode(cdb_net.responses[0])

	def put(self,key,data):
		command = []
		command.append('PUT '+ key +' ' + self.encode(data))
		#command.append('EXIT')
		cdb_net = cdb_net_client(self.servers.get(key), command)
		cdb_net.run()
			
	

